/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compiledriver;

import java.util.ArrayList;

import java.util.ListIterator;
import java.util.Map;

/**
 *
 * @author Mark
 */
public class Expression {
    protected String Id;
    protected ArrayList<Expression> myArguments = new ArrayList<Expression>();
    protected boolean isFunction = false;
    public Expression (ListIterator<String> intext)
    {
        String initialStr = intext.next();
        //tosses out req or ens clause
        if ((initialStr.equals("requires"))
                || (initialStr.equals("ensures")))
        {
            initialStr = intext.next();
        }
        
        Id = initialStr;
        
        initialStr = intext.next();
        if (initialStr.equals("("))
        {
            int numParens = 1;
            isFunction = true;
            while (numParens != 0)
            {
                initialStr = intext.next();
                if (initialStr.equals(")"))
                {
                    numParens--;
                }
                else if (initialStr.equals(","))
                {
                    myArguments.add(new Expression(intext));
                }
                else
                {
                    intext.previous();
                    myArguments.add(new Expression(intext));
                }
            }
        }
        else if (!initialStr.equals(","))
        {
            //just a variable now, move cursor back if its not a comma
            intext.previous();
        }
    }
    
    /**
     * <p>Creates a copy of the original <code>Expression</code> with the arguments
     * that match keys in the <code>Map</code> substituted by their corresponding
     * values</p>
     * @param superExpr the <code>Expression</code> to copy from
     * @param subArgs the arguments to substitute into the new instance
     */
    private Expression(Expression superExpr, Map<String, String> subArgs, int count)
    {
        //NEED check for hashed (#) arguments
        Id = superExpr.Id;
        isFunction = superExpr.isFunction;
        for (Expression expr : superExpr.myArguments)
        {
            myArguments.add(expr.substitute(subArgs, count));
        }
        if (Id.charAt(0) == '#')
        {
            Id = Id.substring(1);
            Id = subArgs.get(Id) + Integer.toString(count-1);
        }
        else if(subArgs.containsKey(Id))
        {
            Id = subArgs.get(Id) + Integer.toString(count);
        }
    }

    public ArrayList<String> getArguments(){
        ArrayList<String> ret = new ArrayList();
        for(Expression s : myArguments){
            if(s.isFunction)
            {
                ret.addAll(s.getArguments());
            }
            else
            {
                if (s.toString().charAt(0) == '#')
                {
                    ret.add(s.toString().substring(1));
                }
                else
                {
                    ret.add(s.toString());
                }
            }
        }
        return ret;
    }
    
    /**
     * <p>Returns a copy of this <code>Expression</code> with the values present in
     * this instance replaced by those in the substitutedArguments param</p>
     * @param substitutedArguments the <code>String</code>s to replace keyed 
     * to their replacements
     * @return A copy of this <code>Expression</code> with substituted arguments
     */
    public Expression substitute(Map<String, String> substitutedArguments, int count)
    {
        Expression retval = new Expression(this, substitutedArguments, count);
        
        return retval;
    }

    /**
     * Get the value of Id
     *
     * @return the value of Id
     */
    public String getId() {
        return Id;
    }

    @Override
    public String toString()
    {
        String retval = Id;
        if (isFunction)
        {
            retval += "(";
            if (!myArguments.isEmpty())
            {
                for (Expression s : myArguments)
                {
                    retval += s.toString() + ",";
                }
                retval = retval.substring(0, retval.length()-1);
            }
            retval += ")";
        }
        return retval;
    }
}